/*
 * @Description: grpc server implementation.
 * @Version: V1.0
 * @Author: zw_1520@163.com
 * @Date: 2024-09-04 08:57:29
 * @LastEditors: zw_1520@163.com
 * @LastEditTime: 2025-04-21 15:51:41
 * Copyright (C) All rights reserved.
 */
#include "robot_grpc_server.h"

ABSL_FLAG(uint16_t, port, 50051, "Server port for the service");

/**
 * @description: RobotGrpcServer constructor
 * @return {*}
 * @author: zw_1520@163.com
 */
RobotGrpcServer::RobotGrpcServer() : Node("robot_grpc_server") {
  RCLCPP_INFO(this->get_logger(), "RobotGrpcServer start.");

  // Inits robot grpc service
  robot_grpc_service_ = new RobotControllerServiceImpl();

  // Starts grpc server thread to await
  std::thread receive_thread(&RobotGrpcServer::StartGrpcServer, this);
  receive_thread.detach();

  // Inits server listen topic
  m_server_message_sub_ = this->create_subscription<std_msgs::msg::String>(
      "/server_send_message", 10,
      std::bind(&RobotGrpcServer::serverMessageCallback, this,
                std::placeholders::_1));
}

/**
 * @description: start grpc server
 * @return {*}
 * @author: zw_1520@163.com
 */
void RobotGrpcServer::StartGrpcServer() {
  uint16_t port = absl::GetFlag(FLAGS_port);
  std::string server_address = absl::StrFormat("0.0.0.0:%d", port);

  // Inints RobotGrpcService service;
  ServerBuilder builder;
  // Listens on the given address without any authentication mechanism.
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  // Registers "service" as the instance through which we'll communicate with
  // clients. In this case it corresponds to an *synchronous* service.
  // builder.RegisterService(robot_grpc_service_);

  builder.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIME_MS,
                             10 * 60 * 1000 /*10 min*/);
  builder.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIMEOUT_MS,
                             20 * 1000 /*20 sec*/);
  builder.AddChannelArgument(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1);
  builder.AddChannelArgument(
      GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS,
      10 * 1000 /*10 sec*/);
  builder.RegisterService(robot_grpc_service_);

  // Assembles the server.
  std::unique_ptr<Server> server(builder.BuildAndStart());
  RCLCPP_INFO(rclcpp::get_logger("stream_data_reactor"),
              "Server listening on %s.", server_address.c_str());

  // Waits for the server to shutdown. Note that some other thread must be
  // responsible for shutting down the server for this call to ever return.
  server->Wait();
}

/**
 * @description: server message callback.
 * @return {*}
 * @author: zw_1520@163.com
 */
void RobotGrpcServer::serverMessageCallback(
    const std_msgs::msg::String::SharedPtr msg) {
  RCLCPP_INFO(this->get_logger(), "Received command: '%s'", msg->data.c_str());

  RobotResponse reply_msg;
  reply_msg.set_msg_id("10011");  // Sends system check message
  reply_msg.set_data(msg->data);
  robot_grpc_service_->sendData(reply_msg);
}